var gdocs = {};
var bgPage = chrome.extension.getBackgroundPage();
var pollIntervalMax = 1000 * 60 * 60; // 1 hour
var requestFailureCount = 0; // used for exponential backoff
var requestTimeout = 1000 * 2; // 5 seconds
var editindex = -1;
var updatecomplete = false;
var DEFAULT_MIMETYPES = {
	'atom': 'application/atom+xml',
	'document': 'text/plain',
	'spreadsheet': 'text/csv',
  	'presentation': 'text/plain',
  	'pdf': 'application/pdf'
};
/**
 * A generic error handler for failed XHR requests.
 * @param {XMLHttpRequest} xhr The xhr request that failed.
 * @param {string} textStatus The server's returned status.
 */
gdocs.handleError = function (xhr, textStatus) {
    util.setExistingErrorMessage('Failed to fetch docs. Please try again.');
};

/**
 * Class to compartmentalize properties of a Google document.
 * @param {Object} entry A JSON representation of a DocList atom entry.
 * @constructor
 */
gdocs.GoogleDoc = function (entry) {
    this.entry = entry;
    this.title = entry.title.$t;
    this.resourceId = entry.gd$resourceId.$t;
    this.contentSrc = entry.content.src;
    this.link = {
        'alternate': gdocs.getLink(entry.link, 'alternate').href
    };
    this.type = gdocs.getCategory(entry.category, 'http://schemas.google.com/g/2005#kind');
    this.content = "";
};

/**
 * Fetches the user's document list.
 * @param {string?} opt_url A url to query the doclist API with. If omitted,
 *     the main doclist feed uri is used.
 */
gdocs.getDocumentList = function (opt_url) {
    var url = opt_url || null;

    var params = {
        'headers': {
            'GData-Version': '3.0'
        }
    };

    if (!url) {
        //bgPage.setIcon({'text': '...'});
        bgPage.docs = []; // Clear document list. We're doing a refresh.
        url = bgPage.DOCLIST_FEED;

        console.log("url: " + url);

        params['parameters'] = {
            'alt': 'json',
            'showfolders': 'true'
        };
    } else {
        var parts = url.split('?');
        if (parts.length > 1) {
            url = parts[0]; // Extract base URI. Params are passed in separately.
            params['parameters'] = util.unstringify(parts[1]);
        }
    }
    console.log(params);
    bgPage.oauth.sendSignedRequest(url, gdocs.processDocListResults, params);
};

/**
 * Callback for processing the JSON feed returned by the DocList API.
 * @param {string} response The server's response.
 * @param {XMLHttpRequest} xhr The xhr request that was made.
 */
gdocs.processDocListResults = function (response, xhr) {
    if (xhr.status != 200) {
        gdocs.handleError(xhr, response);
        return;
    } else {
        requestFailureCount = 0;
    }

    var data = JSON.parse(response);

    for (var i = 0, entry; entry = data.feed.entry[i]; ++i) {
        var doc = new gdocs.GoogleDoc(entry);
        if (doc.type.label == "document") bgPage.docs.push(doc);
    }

    var nextLink = gdocs.getLink(data.feed.link, 'next');
    if (nextLink) {
        gdocs.getDocumentList(nextLink.href); // Fetch next page of results.
    } else {
        gdocs.renderDocList();
    }
};

/**
 * Returns the correct atom link corresponding to the 'rel' value passed in.
 * @param {Array<Object>} links A list of atom link objects.
 * @param {string} rel The rel value of the link to return. For example: 'next'.
 * @return {string|null} The appropriate link for the 'rel' passed in, or null
 *     if one is not found.
 */
gdocs.getLink = function (links, rel) {
    for (var i = 0, link; link = links[i]; ++i) {
        if (link.rel === rel) {
            return link;
        }
    }
    return null;
};

/**
 * Presents the in-memory documents that were fetched from the server as HTML.
 */
gdocs.renderDocList = function () {
    // Construct the doclist div's HTML.
    var html = [];
    for (var i = 0, doc; doc = bgPage.docs[i]; ++i) {
        console.log(doc);
        var link = doc.link['alternate']; 
        var title = doc.title.substring(0,22);
        if(title.length != doc.title.length)
        	title += "...";
        html.push('<div data-index="', i, '">', 
        	'<span class="doc_title">', title, '</span>', 
        	'<span class="view_delete">',
        	'[<a href="javascript:void(0);" ', 
        	'onclick="gdocs.getDocContent(', i, ', \'', link, '\');return false;">view</a> | ', 
        	'<a href="javascript:void(0);" ', 
        	'onclick="gdocs.deleteDoc(', i, ');return false;">delete</a>]', 
        	'</span></div>');
    }
    $("#fetching").hide();
    $('#doclist').html(html.join(''));
    console.log($('#doclist').html());
};

gdocs.getDocContent = function(index, doclink) {
	editindex = index;
	$("#decontent").val("Getting document content...");
	console.log(doclink);
	chrome.tabs.create({url: doclink, active: false});
	chrome.extension.onRequest.addListener(
		function(request, sender, sendResponse) {
			console.log(sender.tab ?
                "from a content script:" + sender.tab.url :
                "from the extension");
            console.log(request.encrypted_content);
            $("#decontent").val(request.encrypted_content);
        	//var encrypted_content = reqeust.encrypted_content;
        	//console.log(encrypted_content);
			//sendResponse({done: "done"});
			chrome.tabs.remove(sender.tab.id);
			$("#decontent").attr("disabled", "true");
			$("#debutton").val("Decrypt");
	});
};

/**
 * Creates a new document in Google Docs.
 */
gdocs.createDoc = function (title, content) {
    var docType = "document";

    //util.displayMsg('Creating doc...');

    var handleSuccess = function (resp, xhr) {
            bgPage.docs.splice(0, 0, new gdocs.GoogleDoc(JSON.parse(resp).entry));
            gdocs.renderDocList();
            //requestFailureCount = 0;
        };

    var params = {
        'method': 'POST',
        'headers': {
            'GData-Version': '3.0',
            'Content-Type': 'multipart/related; boundary=END_OF_PART',
        },
        'parameters': {
            'alt': 'json'
        },
        'body': gdocs.constructContentBody_(title, docType, content, DEFAULT_MIMETYPES[docType], false)
    };
    bgPage.oauth.sendSignedRequest(bgPage.DOCLIST_FEED, handleSuccess, params);
};

/**
 * Updates a document's metadata (title, starred, etc.).
 * @param {gdocs.GoogleDoc} googleDocObj An object containing the document to
 *     update.
 */
gdocs.updateDoc = function(googleDocObj) {
	var docType = "document";
	var handleSuccess = function(resp) {
		console.log(resp);
		updatecomplete = true;
  	};

  	var params = {
    	'method': 'PUT',
    	'headers': {
      		'GData-Version': '3.0',
      		'Content-Type': 'multipart/related; boundary=END_OF_PART',
      		'If-Match': '*'
    	},
    	'body': gdocs.constructContentBody_(googleDocObj.title, docType, googleDocObj.content, DEFAULT_MIMETYPES[docType], false)
	};
  	var url = "https://docs.google.com/feeds/default/media/"+ googleDocObj.resourceId;
  	console.log(url);
  	console.log(params);
  	bgPage.oauth.sendSignedRequest(url, handleSuccess, params);
};

/**
 * A helper for constructing the body of a mime-mutlipart HTTP request.
 * @param {string} title A title for the new document.
 * @param {string} docType The type of document to create.
 *     (eg. 'document', 'spreadsheet', etc.)
 * @param {string} body The body of the HTTP request.
 * @param {string} contentType The Content-Type of the (non-Atom) portion of the
 *     http body.
 * @param {boolean?} opt_starred Whether the document should be starred.
 * @return {string} The Atom xml as a string.
 */
gdocs.constructContentBody_ = function(title, docType, body, contentType,
                                       opt_starred) {
	var body = ['--END_OF_PART\r\n',
              'Content-Type: application/atom+xml;\r\n\r\n',
              gdocs.constructAtomXml_(title, docType, opt_starred), '\r\n',
              '--END_OF_PART\r\n',
              'Content-Type: ', contentType, '\r\n\r\n',
              body, '\r\n',
              '--END_OF_PART--\r\n'].join('');
	console.log(body);
	return body;
};

/**
 * A helper for constructing the raw Atom xml send in the body of an HTTP post.
 * @param {XMLHttpRequest} xhr The xhr request that failed.
 * @param {string} docTitle A title for the document.
 * @param {string} docType The type of document to create.
 *     (eg. 'document', 'spreadsheet', etc.)
 * @param {boolean?} opt_starred Whether the document should be starred.
 * @return {string} The Atom xml as a string.
 */
gdocs.constructAtomXml_ = function(docTitle, docType, opt_starred) {
  var starred = opt_starred || null;

  var starCat = ['<category scheme="http://schemas.google.com/g/2005/labels" ',
                 'term="http://schemas.google.com/g/2005/labels#starred" ',
                 'label="starred"/>'].join('');

  var atom = ["<?xml version='1.0' encoding='UTF-8'?>", 
              '<entry xmlns="http://www.w3.org/2005/Atom">',
              '<category scheme="http://schemas.google.com/g/2005#kind"', 
              ' term="http://schemas.google.com/docs/2007#', docType, '"/>',
              starred ? starCat : '',
              '<title>', docTitle, '</title>',
              '</entry>'].join('');
  return atom;
};

/**
 * Deletes a document from the user's document list.
 * @param {integer} index An index intro the background page's docs array.
 */
gdocs.deleteDoc = function (index) {
    var handleSuccess = function (resp, xhr) {
            requestFailureCount = 0;
            bgPage.docs.splice(index, 1);
            gdocs.renderDocList();
            //bgPage.setIcon({'text': bgPage.docs.length.toString()});
        }

    var params = {
        'method': 'DELETE',
        'headers': {
            'GData-Version': '3.0',
            'If-Match': '*'
        }
    };

    $('#doclist div').eq(index).fadeOut('slow');
    bgPage.oauth.sendSignedRequest(
    bgPage.DOCLIST_FEED + bgPage.docs[index].resourceId, handleSuccess, params);
};

/**
 * Returns the correct atom category corresponding to the scheme/term passed in.
 * @param {Array<Object>} categories A list of atom category objects.
 * @param {string} scheme The category's scheme to look up.
 * @param {opt_term?} An optional term value for the category to look up.
 * @return {string|null} The appropriate category, or null if one is not found.
 */
gdocs.getCategory = function (categories, scheme, opt_term) {
    for (var i = 0, cat; cat = categories[i]; ++i) {
        if (opt_term) {
            if (cat.scheme === scheme && opt_term === cat.term) {
                return cat;
            }
        } else if (cat.scheme === scheme) {
            return cat;
        }
    }
    return null;
};
